using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using FireStarter.Base;
using Firestarter.DB.Schema.BO;
using FireStarterModeller.BO;
using Firestarter.DB.Schema.Logic;
using Habanero.Base;
using Habanero.Base.Exceptions;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using Habanero.DB;
using Habanero.Testability;
using MySql.Data.MySqlClient;
using NUnit.Framework;
using Rhino.Mocks;

namespace Firestarter.DB.Schema.Test.Logic
{
    //TODO: All the scenarios for updating - 
    //      - Add new table
    //      - Remove table
    //      - 
    [TestFixture]
// ReSharper disable InconsistentNaming
    public class TestDBReverseEng_UpdateInfos

    {
        private DBSchemaBuilder _dbSchemaBuilder;
        private TestUtilsSchema _testUtilsSchema;
        private DatabaseReverseEngineerer _databaseReverseEngineerer;
        private DBSchemaExtractor_Fake _schemaExtractorFake;

        [TestFixtureSetUp]
        public  void TestFixtureSetup()
        {
            ClassDef.ClassDefs.Clear();
            string xmlClassDefs = BOBroker.GetClassDefsXml();
            ClassDef.ClassDefs.Add(new XmlClassDefsLoader(xmlClassDefs, new DtdLoader()).LoadClassDefs());

            _dbSchemaBuilder = new DBSchemaBuilder();
        }

        [SetUp]
        public  void SetupTest()
        {
            _schemaExtractorFake = new DBSchemaExtractor_Fake();
            _databaseReverseEngineerer = CreateDatabaseReverseEngineerer(_schemaExtractorFake);
            _testUtilsSchema = new TestUtilsSchema(_dbSchemaBuilder);
            BORegistry.DataAccessor = new DataAccessorInMemory();
            // Reset the UIExceptionNotifier before each test as some test change this from the default RethrowingExceptionNotifier
            GlobalRegistry.UIExceptionNotifier = new RethrowingExceptionNotifier();
        }

        #region TestUtilityMethods

        //[Test]
        //public void TestTables_HasNoTables_WithoutPopulateCall()
        //{
        //    //-------------Setup Test Pack ------------------
        //    const string tableName = "TestTable";
        //    _dbSchemaBuilder.CreateDatabaseTableWithIDAndNameField(tableName);
        //    DBDatabase databaseInfo = new DBDatabase(_databaseConnection);
        //    //-------------Test Pre-conditions --------------
        //    //-------------Execute test ---------------------
        //    List<Table> tableInfos = databaseInfo.Tables;
        //    //-------------Test Result ----------------------
        //    Assert.AreEqual(0, tableInfos.Count, "There should be zero table infos as populate has not been called.");
        //}

        [Test]
        public void Test_ConvertDBNullToNull()
        {
            //---------------Set up test pack-------------------
            string value = GetRandomString();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object nullValue = DBUtilities.ConvertDBNullToNull(DBNull.Value);
            object nonNullValue = DBUtilities.ConvertDBNullToNull(value);
            //---------------Test Result -----------------------
            Assert.AreEqual(null, nullValue);
            Assert.AreEqual(value, nonNullValue);
        }

        [Test]
        public void Test_ConvertDBNullToNullDateTime()
        {
            //---------------Set up test pack-------------------
            DateTime? value = DateTime.Now;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object nullValue = DBUtilities.ConvertDBNullToNullDateTime(DBNull.Value);
            object nonNullValue = DBUtilities.ConvertDBNullToNullDateTime(value);
            //---------------Test Result -----------------------
            Assert.AreEqual(null, nullValue);
            Assert.AreEqual(value, nonNullValue);
        }

        [Test]
        public void Test_GetCharDataLength_FromCharMaxLength()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            const int expectedDataLength = 12;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), "CHAR(38)", expectedDataLength);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            long dataLength = DatabaseReverseEngineerer.GetCharDataLength(dataTable.Rows[0]);

            //---------------Test Result -----------------------
            Assert.AreEqual(expectedDataLength, dataLength);
        }

        [Test]
        public void Test_GetCharDataLength_FromDataType_12()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            const int expectedDataLength = 12;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), "CHAR(" + expectedDataLength + ")", 0);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            long dataLength = DatabaseReverseEngineerer.GetCharDataLength(dataTable.Rows[0]);

            //---------------Test Result -----------------------
            Assert.AreEqual(expectedDataLength, dataLength);
        }

        [Test]
        public void Test_GetCharDataLength_FromDataType_33()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            const int expectedDataLength = 33;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), "CHAR(" + expectedDataLength + ")", 0);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            long dataLength = DatabaseReverseEngineerer.GetCharDataLength(dataTable.Rows[0]);

            //---------------Test Result -----------------------
            Assert.AreEqual(expectedDataLength, dataLength);
        }

        [Test]
        public void Test_GetCharDataLength_FromColumnType_12()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            const int expectedDataLength = 12;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), "CHAR",0);
            dataTable.Columns.Add("ColumnType");
            dataTable.Rows[0]["ColumnType"] = "CHAR(" + expectedDataLength + ")";
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            long dataLength = DatabaseReverseEngineerer.GetCharDataLength(dataTable.Rows[0]);

            //---------------Test Result -----------------------
            Assert.AreEqual(expectedDataLength, dataLength);
        }

        [Test]
        public void Test_GetCharDataLength_FromColumnType_33()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            const int expectedDataLength = 33;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), "CHAR", 0);
            dataTable.Columns.Add("ColumnType");
            dataTable.Rows[0]["ColumnType"] = "CHAR(" + expectedDataLength + ")";

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            long dataLength = DatabaseReverseEngineerer.GetCharDataLength(dataTable.Rows[0]);

            //---------------Test Result -----------------------
            Assert.AreEqual(expectedDataLength, dataLength);
        }

        //TODO: Check where this goes.
        [Test,Ignore("Need clarity as to where this test should go.")]
        public void Test_OpenConnection_DatabaseDoesntExist()
        {
            //-------------Setup Test Pack ------------------
            DatabaseConfig databaseConfig = new DatabaseConfig
                ("MySql", "localhost", "bobsdatabasewhichdoesntexist", "root", "root", "3306");
            DBDatabase dbDatabase = new DBDatabase(databaseConfig.GetDatabaseConnection());
            dbDatabase.Catalog = null;
            dbDatabase.Schema = databaseConfig.Database;

            _schemaExtractorFake.TablesDataTable = DBSchemaBuilder.GetTablesDataTable();

            string errors;
            bool databaseExists = dbDatabase.DatabaseExists(out errors);
            //-------------Test Pre-conditions -------------
            Assert.IsFalse(databaseExists);

            //-------------Execute test ---------------------
            try
            {
                _databaseReverseEngineerer.PopulateDBDatabase(dbDatabase);
                Assert.Fail("Error should be thrown");
            }

                //-------------Test Result ----------------------
            catch (MySqlException ex)
            {
                StringAssert.Contains("Unknown database", ex.Message);
            }
        }

        [Test]
        public void Test_DBTypeConverter_GetSet()
        {
            //---------------Set up test pack-------------------
            DBTypeConverter expectedDbTypeConverter = new DBTypeConverter(null);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.DBTypeConverter=expectedDbTypeConverter;
            //---------------Test Result -----------------------
            Assert.AreSame(expectedDbTypeConverter, _databaseReverseEngineerer.DBTypeConverter);
        }

        #endregion

        #region Test PopulateTables

        [Test]
        public void Test_PopulateTables_OneTable()
        {
            //---------------Set up test pack-------------------
            const string tableType = "Base Table";
            const string tableName = "TableName";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName, tableType);
            _schemaExtractorFake.TablesDataTable = dataTable;
            DBDatabase dbDatabase = new DBDatabase();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            DBTable dbTable = dbDatabase.Tables[0];
            Assert.AreEqual(tableName, dbTable.TableName);
            Assert.AreEqual("DBTable", dbTable.TableType);
        }

        [Test]
        public void Test_PopulateTables_WithDefaultSchemaName_ShouldSetSchemaOnTable()
        {
            //---------------Set up test pack-------------------
            const string tableType = "Base Table";
            const string tableName = "TableName";
            
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName, tableType);
            _schemaExtractorFake.TablesDataTable = dataTable;
            DBDatabase dbDatabase = new DBDatabase();
            dbDatabase.Schema = RandomValueGen.GetRandomString();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);
            
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            DBTable dbTable = dbDatabase.Tables[0];
            Assert.AreEqual(tableName, dbTable.TableName);
            Assert.AreEqual("DBTable", dbTable.TableType);
            Assert.AreEqual(dbTable.SchemaName, DBSchemaBuilder.DefaultSchemaName);
        }
        [Test]
        public void Test_PopulateTables_WithDefaultSchemaName_WhenView_ShouldSetSchemaOnView()
        {
            //---------------Set up test pack-------------------
            const string tableType = "VIEW";
            const string tableName = "TableName";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName, tableType);
            _schemaExtractorFake.TablesDataTable = dataTable;
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.ImportViews = true;
            //---------------Assert Precondition----------------
            DataRow dataRow = dataTable.Rows[0];
            dataRow.AssertIsView();
            Assert.IsTrue(_databaseReverseEngineerer.ImportViews);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Views.Count);
            DBView dbView = dbDatabase.Views[0];
            Assert.AreEqual(tableName, dbView.TableName);
            Assert.AreEqual("DBView", dbView.TableType);
            Assert.AreEqual(dbView.SchemaName, DBSchemaBuilder.DefaultSchemaName);
        }
        [Test]
        public void Test_PopulateTables_WithCustomSchemaName_ShouldSetSchemaOnTable()
        {
            //---------------Set up test pack-------------------
            const string tableType = "Base Table";
            const string tableName = "TableName";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            var expectedSchemaName = GetRandomString();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, GetRandomString(), expectedSchemaName, tableName, tableType);
            _schemaExtractorFake.TablesDataTable = dataTable;
            DBDatabase dbDatabase = new DBDatabase();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);
            
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            DBTable dbTable = dbDatabase.Tables[0];
            Assert.AreEqual(tableName, dbTable.TableName);
            Assert.AreEqual("DBTable", dbTable.TableType);
            Assert.AreEqual(expectedSchemaName, dbTable.SchemaName);
        }
        [Test]
        public void Test_PopulateTables_WithCustomSchemaName_WhenView_ShouldSetSchemaOnView()
        {
            //---------------Set up test pack-------------------
            const string tableType = "VIEW";
            const string tableName = "TableName";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            var expectedSchemaName = GetRandomString();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, GetRandomString(), expectedSchemaName, tableName, tableType);
            _schemaExtractorFake.TablesDataTable = dataTable;
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.ImportViews = true;
            //---------------Assert Precondition----------------
            DataRow dataRow = dataTable.Rows[0];
            dataRow.AssertIsView();
            Assert.AreEqual(expectedSchemaName, dataRow[DBSchemaTemplate.Naming.TableSchema].ToString());
            Assert.IsTrue(_databaseReverseEngineerer.ImportViews);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Views.Count);
            DBView dbView = dbDatabase.Views[0];
            Assert.AreEqual(dbView.SchemaName, expectedSchemaName);  
        }

        [Test]
        public void Test_PopulateTables_OneView_ShouldAddView()
        {
            //---------------Set up test pack-------------------
            const string tableType = "View";
            const string tableName = "TableName";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName, tableType);
            _schemaExtractorFake.TablesDataTable = dataTable;
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.ImportViews = true;
            //---------------Assert Precondition----------------
            dataTable.Rows[0].AssertIsView();
            Assert.IsTrue(_databaseReverseEngineerer.ImportViews);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);

            //---------------Test Result -----------------------
            Assert.AreEqual(0, dbDatabase.Tables.Count);
            Assert.AreEqual(1, dbDatabase.Views.Count);
            DBView dbView = dbDatabase.Views[0];
            Assert.AreEqual(tableName, dbView.TableName);
            Assert.AreEqual("DBView", dbView.TableType);
        }
        [Test]
        public void Test_PopulateTables_TwoTable()
        {
            //---------------Set up test pack-------------------
            const string tableName1 = "TableName1";
            const string tableName2 = "TableName2";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1);
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2);
            _schemaExtractorFake.TablesDataTable = dataTable;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.PopulateTables(dbDatabase);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, dbDatabase.Tables.Count);
            DBTable dbTable = dbDatabase.GetTable(tableName1);
            Assert.IsNotNull(dbTable);
            dbTable = dbDatabase.GetTable(tableName2);
            Assert.IsNotNull(dbTable);
        }
        [Test]
        public void Test_PopulateTables_TwoView()
        {
            //---------------Set up test pack-------------------
            const string tableName1 = "TableName1";
            const string tableName2 = "TableName2";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1, "VIEW");
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2, "VIEW");
            _schemaExtractorFake.TablesDataTable = dataTable;
            _databaseReverseEngineerer.ImportViews = true;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.PopulateTables(dbDatabase);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, dbDatabase.Views.Count);
            DBView dbView = dbDatabase.GetView(tableName1);
            Assert.IsNotNull(dbView);
            dbView = dbDatabase.GetView(tableName2);
            Assert.IsNotNull(dbView);
        }

        [Test]
        public void Test_PopulateTables_TwoTable_OneTablecalledsysdiagram_ShouldNotImportsysdiagram_FixBug808()
        {
            //---------------Set up test pack-------------------
            const string tableName1 = "TableName1";
            const string tableName2 = "sysdiagrams";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1);
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2);
            _schemaExtractorFake.TablesDataTable = dataTable;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.PopulateTables(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            DBTable dbTable = dbDatabase.GetTable(tableName1);
            Assert.IsNotNull(dbTable);
            dbTable = dbDatabase.GetTable(tableName2);
            Assert.IsNull(dbTable);
        }
        [Test]
        public void Test_PopulateTables_TwoTable_OneTablecalleddtproperties_ShouldNotImportdtproperties_FixBug825()
        {
            //---------------Set up test pack-------------------
            const string tableName1 = "TableName1";
            const string tableName2 = "dtproperties";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1);
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2);
            _schemaExtractorFake.TablesDataTable = dataTable;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            DBDatabase dbDatabase = new DBDatabase();
            _databaseReverseEngineerer.PopulateTables(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            DBTable dbTable = dbDatabase.GetTable(tableName1);
            Assert.IsNotNull(dbTable);
            dbTable = dbDatabase.GetTable(tableName2);
            Assert.IsNull(dbTable);
        }

        [Test]
        public void Test_PopulateTables_OneViewOneTable_ImportViewsIsFalse_ShouldOnlyImportTable()
        {
            //---------------Set up test pack-------------------
           // DBDatabase
            const string tableName1 = "TableName1";
            const string tableType = "BASE TABLE";
            const string tableName2 = "TableName2";
            const string viewType = "VIEW";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1, tableType);
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2, viewType);
            _schemaExtractorFake.TablesDataTable = dataTable;

            var reverseEngineeringSettings = new ReverseEngineeringSettings();
            DBDatabase dbDatabase = GetDBDatabase();
            var databaseReverseEngineerer = new DatabaseReverseEngineerer(reverseEngineeringSettings, _schemaExtractorFake);
            //---------------Assert Precondition----------------
            Assert.IsFalse(reverseEngineeringSettings.ImportViews.GetValueOrDefault());
            Assert.IsTrue(reverseEngineeringSettings.ImportTables.GetValueOrDefault());
            //---------------Execute Test ----------------------

            databaseReverseEngineerer.PopulateTables(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            Assert.IsNotNull(dbDatabase.GetTable(tableName1));

            Assert.AreEqual(0, dbDatabase.Views.Count);
            Assert.IsNull(dbDatabase.GetView(tableName2));
        }
        [Test]
        public void Test_PopulateTables_OneViewOneTable_ImportBothIsTrue_ShouldImportBoth()
        {
            //---------------Set up test pack-------------------
            const string tableName1 = "TableName1";
            const string tableType = "BASE TABLE";
            const string viewType = "VIEW";
            const string tableName2 = "TableName2";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1, tableType);
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2, viewType);
            _schemaExtractorFake.TablesDataTable = dataTable;

            var reverseEngineeringSettings = new ReverseEngineeringSettings {ImportViews = true};
            DBDatabase dbDatabase = GetDBDatabase();
            
            var databaseReverseEngineerer = new DatabaseReverseEngineerer(reverseEngineeringSettings, _schemaExtractorFake);
            //---------------Assert Precondition----------------
            Assert.IsTrue(reverseEngineeringSettings.ImportViews.GetValueOrDefault());
            Assert.IsTrue(reverseEngineeringSettings.ImportTables.GetValueOrDefault());
            //---------------Execute Test ----------------------

            databaseReverseEngineerer.PopulateTables(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            Assert.IsNotNull(dbDatabase.GetTable(tableName1));

            Assert.AreEqual(1, dbDatabase.Views.Count);
            Assert.IsNotNull(dbDatabase.GetView(tableName2));
        }
        [Test]
        public void Test_PopulateTables_OneViewOneTable_ImportTablesIsFalse_ShouldImportView()
        {
            //---------------Set up test pack-------------------
           // DBDatabase
            const string tableName1 = "TableName1";
            const string tableType = "BASE TABLE";
            const string viewType = "VIEW";
            const string tableName2 = "TableName2";
            DataTable dataTable = DBSchemaBuilder.GetTablesDataTable();
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName1, tableType);
            _dbSchemaBuilder.CreateTableDataRow(dataTable, tableName2, viewType);
            _schemaExtractorFake.TablesDataTable = dataTable;

            DBDatabase dbDatabase = GetDBDatabase();

            var reverseEngineeringSettings = new ReverseEngineeringSettings {ImportViews = true, ImportTables = false};
            var databaseReverseEngineerer = new DatabaseReverseEngineerer(reverseEngineeringSettings, _schemaExtractorFake);
            //---------------Assert Precondition----------------
            Assert.IsTrue(reverseEngineeringSettings.ImportViews.GetValueOrDefault());
            Assert.IsFalse(reverseEngineeringSettings.ImportTables.GetValueOrDefault());
            //---------------Execute Test ----------------------

            databaseReverseEngineerer.PopulateTables(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, dbDatabase.Tables.Count);
            Assert.IsNull(dbDatabase.GetTable(tableName1));

            Assert.IsNotNull(dbDatabase.GetView(tableName2));
        }

        private DBDatabase GetDBDatabase()
        {
            return new DBDatabase();
        }
        #endregion

        #region Test PopulateTable

        [Test]
        public void Test_PopulateDBDatabase_TwoColumnsInTable()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            var tableName = GetRandomString();
            DataTable dataTable = GetColumnsDataTable_TwoColumns(tableName, columnName1, columnName2);
            DataTable tableDataTableOneTable = GetTableDataTable_OneTable(tableName);

            var dbDatabase = new DBDatabase();
            _schemaExtractorFake.TablesDataTable = tableDataTableOneTable;
            _schemaExtractorFake.ColumnsDataTable = dataTable; 
            var databaseReverseEngineerer = GetDatabaseReverseEngineererSpy();
            databaseReverseEngineerer.ImportViews = true;
            //--------------Assert PreConditions----------------
            Assert.IsTrue(databaseReverseEngineerer.ImportViews);
            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            databaseReverseEngineerer.PopulateDBDatabase(dbDatabase);

            //---------------Test Result -----------------------

            Assert.AreEqual(0, dbDatabase.Views.Count);
            Assert.AreEqual(1, dbDatabase.Tables.Count);
            var dbTable = dbDatabase.Tables[0];
            Assert.AreEqual(2, dbTable.Columns.Count);
            Assert.IsNotNull(dbTable.GetColumn(columnName1));
            Assert.IsNotNull(dbTable.GetColumn(columnName2));
        }


        [Test]
        public void Test_PopulateDBDatabase_TwoColumnsInView()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            var tableName = GetRandomString();
            DataTable dataTable = GetColumnsDataTable_TwoColumns(tableName, columnName1, columnName2);
            DataTable tableDataTableOneTable = _dbSchemaBuilder.CreateTableDataTable_OneView(tableName);

            _schemaExtractorFake.TablesDataTable = tableDataTableOneTable;
            _schemaExtractorFake.ColumnsDataTable = dataTable;
            var dbDatabase = new DBDatabase();

            var databaseReverseEngineerer = GetDatabaseReverseEngineererSpy();
            databaseReverseEngineerer.ImportViews = true;
            //--------------Assert PreConditions----------------
            Assert.IsTrue(databaseReverseEngineerer.ImportViews);
            //---------------Execute Test ----------------------
            databaseReverseEngineerer.PopulateDBDatabase(dbDatabase);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, dbDatabase.Tables.Count);
            Assert.AreEqual(1, dbDatabase.Views.Count);
            var dbView = dbDatabase.Views[0];
            Assert.AreEqual(2, dbView.Columns.Count);
            Assert.IsNotNull(dbView.GetColumn(columnName1));
            Assert.IsNotNull(dbView.GetColumn(columnName2));
            Assert.AreEqual(2, dbView.Columns.Count);
            Assert.IsNotNull(dbView.GetColumn(columnName1));
            Assert.IsNotNull(dbView.GetColumn(columnName2));
        }

        private DataTable GetTableDataTable_OneTable(string tableName)
        {
            return _dbSchemaBuilder.CreateTableDataTable_OneTable(tableName);
        }

        private DataTable GetColumnsDataTable_TwoColumns(string tableName, string columnName1, string columnName2)
        {
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName2);
            return dataTable;
        }
        [Test]
        public void Test_PopulateDBDatabase_nullDBINfo()
        {
            //-------------Setup Test Pack ------------------
            const DBDatabase databaseInfo = null;
            //-------------Test Pre-conditions --------------
            //-------------Execute test ---------------------
            try
            {
                _databaseReverseEngineerer.PopulateDBDatabase(databaseInfo);
                Assert.Fail("Should raise an error");
            }
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("dbDatabase", ex.Message);
            }
        }
        #endregion

        #region Test PopulateTable

        [Test]
        public void Test_PopulateTable_NoDatabaseInfo_ThrowsException()
        {
            //---------------Set up test pack-------------------
            DBTable dbTable = new DBTable();
            //---------------Assert Precondition----------------
            Assert.IsNull(dbTable.Database);
            //---------------Execute Test ----------------------
            try
            {
                _databaseReverseEngineerer.PopulateTable(dbTable);
                Assert.Fail("Should raise an error");
            }
            catch (NullReferenceException ex)
            {
                StringAssert.Contains("does not have a reference to DBDatabase", ex.Message);
            }
        }

        [Test]
        public void Test_PopulateTable_TwoColumnsInTable()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            var tableName = GetRandomString();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            DBTable dbTable = new DBTable { Database = new DBDatabase(), TableName = tableName };
            var databaseReverseEngineerer = GetDatabaseReverseEngineererSpy();
            databaseReverseEngineerer.ExtractColumnData(dataTable);
            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            databaseReverseEngineerer.PopulateTable(dbTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, dbTable.Columns.Count);
            Assert.IsNotNull(dbTable.GetColumn(columnName1));
            Assert.IsNotNull(dbTable.GetColumn(columnName2));
        }
        [Test]
        public void Test_PopulateView_TwoColumnsInTable()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            var tableName = GetRandomString();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            DBView dbView = new DBView { Database = new DBDatabase(), TableName = tableName};
            var databaseReverseEngineerer = GetDatabaseReverseEngineererSpy();
            databaseReverseEngineerer.ExtractColumnData(dataTable);
            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            databaseReverseEngineerer.PopulateView(dbView);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, dbView.Columns.Count);
            Assert.IsNotNull(dbView.GetColumn(columnName1));
            Assert.IsNotNull(dbView.GetColumn(columnName2));
        }
        [Test]
        public void Test_PopulateView_TwoColumnsInTable_OneNotForTable_ShouldImportOne()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            var tableName = GetRandomString();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, tableName, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            DBView dbView = new DBView { Database = new DBDatabase(), TableName = tableName};
            var databaseReverseEngineerer = GetDatabaseReverseEngineererSpy();
            databaseReverseEngineerer.ExtractColumnData(dataTable);
            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            databaseReverseEngineerer.PopulateView(dbView);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbView.Columns.Count);
            Assert.IsNotNull(dbView.GetColumn(columnName1));
            Assert.IsNull(dbView.GetColumn(columnName2));
        }

        private DatabaseReverseEngineererSpy GetDatabaseReverseEngineererSpy()
        {
            return new DatabaseReverseEngineererSpy(new ReverseEngineeringSettings(), _schemaExtractorFake);
        }

        #endregion

        #region Test PopulateColumns

        [Test]
        public void Test_PopulateColumns_IdColumn()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            string columnName = GetRandomString() + "ID";
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName, "CHAR",38);
            DBTable dbTable = new DBTable();
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateColumns(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbTable.Columns.Count);
            DBColumn dbColumn = dbTable.Columns[0];
            Assert.AreEqual(columnName, dbColumn.ColumnName);
            Assert.AreEqual("char".ToUpper(), dbColumn.DataType);
            Assert.AreEqual(38, dbColumn.DataLength);
        }

        [Test]
        public void Test_PopulateColumns_TwoColumnsInTable()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            DBTable dbTable = new DBTable();

            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateColumns(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, dbTable.Columns.Count);
            Assert.IsNotNull(dbTable.GetColumn(columnName1));
            Assert.IsNotNull(dbTable.GetColumn(columnName2));
        }

        [Test]
        public void Test_PopulateColumns_TwoColumnsInTable_OutOfMany()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DBTable dbTable = new DBTable();
            dbTable.TableName = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, dbTable.TableName, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), columnName2);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, dbTable.TableName, columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            //--------------Assert PreConditions----------------
            Assert.AreEqual(3, dataTable.Rows.Count);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateColumns(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, dbTable.Columns.Count);
            Assert.IsNotNull(dbTable.GetColumn(columnName1));
            Assert.IsNotNull(dbTable.GetColumn(columnName2));
        }

        [Test]
        public void Test_PopulateColumns_ConvertsCustomType()
        {
            //---------------Set up test pack-------------------
            string dataType = GetRandomString();
            string customDataType = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            string columnName = customDataType;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName, dataType, 38);
            DBTable dbTable = new DBTable();
            //_schemaExtractorFake.ColumnsDataTable = dataTable;

            BusinessObjectCollection<TypeMapping> typeMappings = new BusinessObjectCollection<TypeMapping>();
            TypeMapping typeMapping = new TypeMapping { FromType = dataType, ToType = customDataType };
            typeMappings.Add(typeMapping);
            DBTypeConverter typeConverter = new DBTypeConverter(typeMappings);
            _databaseReverseEngineerer.DBTypeConverter = typeConverter;
            //---------------Assert Precondition----------------
            
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateColumns(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbTable.Columns.Count);
            DBColumn dbColumn = dbTable.Columns[0];
            Assert.AreEqual(columnName, dbColumn.ColumnName);
            Assert.AreEqual(customDataType, dbColumn.DataType);
            Assert.AreEqual(38, dbColumn.DataLength);
        }

        [Test]
        public void Test_PopulateColumns_WhenCharLengthGTIntMax_ShouldConvertToIntMax()
        {
            //---------------Set up test pack-------------------
            const string dataType = "Char";
            string customDataType = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            string columnName = customDataType;
            const long maxCharLength = long.MaxValue - 6;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName, dataType, maxCharLength);
            DBTable dbTable = new DBTable();
            BusinessObjectCollection<TypeMapping> typeMappings = new BusinessObjectCollection<TypeMapping>();
            TypeMapping typeMapping = new TypeMapping { FromType = dataType, ToType = customDataType };
            typeMappings.Add(typeMapping);
            DBTypeConverter typeConverter = new DBTypeConverter(typeMappings);
            _databaseReverseEngineerer.DBTypeConverter = typeConverter;
            //---------------Assert Precondition----------------
            DataRow dataRow = dataTable.Rows.OfType<DataRow>().First();
            Assert.IsNotNull(dataRow);
            Assert.Greater(Convert.ToInt64(dataRow[DBSchemaTemplate.Naming.CharacterMaximumLength]), int.MaxValue);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateColumns(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbTable.Columns.Count);
            DBColumn dbColumn = dbTable.Columns[0];
            Assert.AreEqual(columnName, dbColumn.ColumnName);
            Assert.AreEqual(customDataType, dbColumn.DataType);
            Assert.AreEqual(int.MaxValue, dbColumn.DataLength);
        }
        #endregion

        #region Exception Notifier Tests
        /*
         These tests are to test that GlobalRegistry.UIExceptionNotifier will be used to handle errors in the low level methods
         of DatabaseReverseEngineerer.  The intention is to us a RecordingExceptionNotifier to log exceptions instead of allowing
         a single exception to bubble back up leaving the resulting database in an inconsistent state
         */

        [Test]
        public void Test_PopulateDBDatabase_WhenInputIsNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DBDatabase dbDatabase = null;
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbDatabase);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateDBDatabase(dbDatabase);

            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateDBDatabase", errorMessage);
        }

        [Ignore("Test will fail as the inputs are no longer within the try catch in PopulateTables the calling method will however catch this")] //TODO Andrew Russell 29 Oct 2010: Ignored Test - Test will fail as the inputs are no longer within the try catch in PopulateTables the calling method will however catch this
        [Test]
        public void Test_PopulateTables_WhenInputsAreNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DBTable dataTable = null;
            DBDatabase dbDatabase = null;
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbDatabase);
            Assert.IsNull(dataTable);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTables(dbDatabase);

            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateTables", errorMessage);
        }

        [Test]
        public void Test_PopulateTable_WhenInputIsNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DBTable dbTable = null;
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbTable);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateTable(dbTable);

            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateTable", errorMessage);
        }

        [Test]
        public void Test_PopulateColumns_WhenInputsAreNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = null;
            DBTable dbTable = null;
            bool wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbTable);
            Assert.IsNull(dataTable);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateColumns(dbTable, dataTable);
            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateColumns", errorMessage);

        }

        [Test]
        public void Test_PopulatePrimaryKeyInfos_WhenInputsAreNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = null;
            DBTable dbTable = null; 
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });

            //--------------Assert PreConditions----------------
            Assert.IsNull(dbTable);
            Assert.IsNull(dataTable);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulatePrimaryKeyInfos(dbTable, dataTable);
            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle); 
            Assert.AreEqual("Exception occurred in PopulatePrimaryKeyInfos", errorMessage);

        }

        [Test]
        public void Test_PopulatePrimaryKeyInfos_WhenFieldsNotLoadedAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            var columnName1 = GetRandomString();
            var dataTable = DBSchemaBuilder.GetPrimaryKeyColumnsDataTable();
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, columnName1);
            var dbTable = new DBTable();
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            Exception thrownEx = null;
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                    thrownEx = ex;
                });

            //--------------Assert PreConditions----------------
            
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulatePrimaryKeyInfos(dbTable, dataTable);
            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in UpdateDBTable", errorMessage);
            StringAssert.Contains("You cannot get the key for the table  since the tables columns have not been loaded yet", thrownEx.Message);
        }

        [Test]
        public void Test_PopulateUniqueKeyInfos_WhenInputsAreNullNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            DataTable dataTable = null;
            DBTable dbTable = null; 
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });

            //--------------Assert PreConditions----------------
            Assert.IsNull(dbTable);
            Assert.IsNull(dataTable);
            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            _databaseReverseEngineerer.PopulateUniqueKeyInfos(dbTable, dataTable);

            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateUniqueKeyInfos", errorMessage);
        }

        [Test]
        public void Test_PopulateView_WhenInputIsNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DBView dbView = null;
            var wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbView);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateView(dbView);

            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateView", errorMessage);
        }

        [Ignore("Test will fail as the inputs are no longer within the try catch in PopulateViewColumns the calling method will however catch this")] //TODO Andrew Russell 29 Oct 2010: Ignored Test - Test will fail as the inputs are no longer within the try catch in PopulateViewColumns the calling method will however catch this
        [Test]
        public void Test_PopulateViewColumns_WhenInputsAreNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = null;
            DBView dbView = null;
            bool wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbView);
            Assert.IsNull(dataTable);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateViewColumns(dbView, dataTable);
            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateViewColumns", errorMessage);
        }

        [Test]
        public void Test_PopulateForeignKeys_WhenInputsAreNullAndDelegatedExceptionNotifierSetup_ShouldNotifyOfException()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = null;
            DBTable dbTable = null;
            bool wasCalled = false;
            var errorMessage = "";
            var errorTitle = "";
            GlobalRegistry.UIExceptionNotifier = new DelegatedExceptionNotifier(
                (ex, furtherMessage, title) =>
                {
                    wasCalled = true;
                    errorMessage = furtherMessage;
                    errorTitle = title;
                });
            //---------------Assert Precondition----------------
            Assert.IsNull(dbTable);
            Assert.IsNull(dataTable);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateForeignKeys(dbTable, dataTable);
            //---------------Test Result -----------------------
            AssertExceptionNotifierWasCalled(wasCalled, errorTitle);
            Assert.AreEqual("Exception occurred in PopulateForeignKeys", errorMessage);           
        }

        private static void AssertExceptionNotifierWasCalled(bool wasCalled, string errorTitle)
        {
            Assert.IsTrue(wasCalled);
            Assert.AreEqual("SchemaMerger", errorTitle);
        }

        #endregion

        #region View PopulateViewColumns
        [Test]
        public void TestPopulateColumns_WhenView__IdColumn()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            string columnName = GetRandomString() + "ID";
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName, "CHAR", 38);
            var view = new DBView();
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateViewColumns(view, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, view.Columns.Count);
            DBViewColumn dbColumn = view.Columns[0];
            Assert.AreEqual(columnName, dbColumn.ColumnName);
            Assert.AreEqual("char".ToUpper(), dbColumn.DataType);
            Assert.AreEqual(38, dbColumn.DataLength);
        }

        [Test]
        public void TestPopulateColumns_WhenView__TwoColumnsInTable()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            var view = new DBView();

            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateViewColumns(view, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, view.Columns.Count);
            Assert.IsNotNull(view.GetColumn(columnName1));
            Assert.IsNotNull(view.GetColumn(columnName2));
        }

        [Test]
        public void TestPopulateColumns_WhenView__TwoColumnsInTable_OutOfMany()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            var view = new DBView();
            view.TableName = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, view.TableName, columnName1);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, GetRandomString(), columnName2);
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, view.TableName, columnName2);
            //_schemaExtractorFake.ColumnsDataTable = dataTable;
            //--------------Assert PreConditions----------------
            Assert.AreEqual(3, dataTable.Rows.Count);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateViewColumns(view, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, view.Columns.Count);
            Assert.IsNotNull(view.GetColumn(columnName1));
            Assert.IsNotNull(view.GetColumn(columnName2));
        }

        [Test]
        public void TestPopulateColumns_WhenView__ConvertsCustomType()
        {
            //---------------Set up test pack-------------------
            string dataType = GetRandomString();
            string customDataType = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            string columnName = customDataType;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName, dataType, 38);
            var view = new DBView();
            //_schemaExtractorFake.ColumnsDataTable = dataTable;

            BusinessObjectCollection<TypeMapping> typeMappings = new BusinessObjectCollection<TypeMapping>();
            TypeMapping typeMapping = new TypeMapping { FromType = dataType, ToType = customDataType };
            typeMappings.Add(typeMapping);
            DBTypeConverter typeConverter = new DBTypeConverter(typeMappings);
            _databaseReverseEngineerer.DBTypeConverter = typeConverter;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateViewColumns(view, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, view.Columns.Count);
            DBViewColumn dbColumn = view.Columns[0];
            Assert.AreEqual(columnName, dbColumn.ColumnName);
            Assert.AreEqual(customDataType, dbColumn.DataType);
            Assert.AreEqual(38, dbColumn.DataLength);
        }

        [Test]
        public void TestPopulateColumns_WhenView__WhenCharLengthGTIntMax_ShouldConvertToIntMax()
        {
            //---------------Set up test pack-------------------
            const string dataType = "Char";
            string customDataType = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetColumnsDataTable();
            string columnName = customDataType;
            const long maxCharLength = long.MaxValue - 6;
            _dbSchemaBuilder.CreateColumnDataRow(dataTable, columnName, dataType, maxCharLength);
            var view = new DBView();
            BusinessObjectCollection<TypeMapping> typeMappings = new BusinessObjectCollection<TypeMapping>();
            TypeMapping typeMapping = new TypeMapping { FromType = dataType, ToType = customDataType };
            typeMappings.Add(typeMapping);
            DBTypeConverter typeConverter = new DBTypeConverter(typeMappings);
            _databaseReverseEngineerer.DBTypeConverter = typeConverter;
            //---------------Assert Precondition----------------
            DataRow dataRow = dataTable.Rows.OfType<DataRow>().First();
            Assert.IsNotNull(dataRow);
            Assert.Greater(Convert.ToInt64(dataRow[DBSchemaTemplate.Naming.CharacterMaximumLength]), int.MaxValue);
            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateViewColumns(view, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, view.Columns.Count);
            DBViewColumn dbColumn = view.Columns[0];
            Assert.AreEqual(columnName, dbColumn.ColumnName);
            Assert.AreEqual(customDataType, dbColumn.DataType);
            Assert.AreEqual(int.MaxValue, dbColumn.DataLength);
        }

        #endregion

        #region PrimaryKey

        [Test]
        public void TestUpdatePrimaryKeyInfos_FieldsNotLoaded()
        {
            //This test shows that a Primary Key is not an alternate key.
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetPrimaryKeyColumnsDataTable();
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, columnName1);
            //_schemaExtractorFake.PrimaryKeysDataTable = dataTable;
            DBTable dbTable = new DBTable();
            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            try
            {
                _databaseReverseEngineerer.PopulatePrimaryKeyInfos(dbTable, dataTable);
                Assert.Fail("expected Err");
            }
            //---------------Test Result -----------------------
            catch (HabaneroApplicationException ex)
            {
                StringAssert.Contains("You cannot get the key for the table ", ex.Message);
                StringAssert.Contains("since the tables columns have not been loaded", ex.Message);
            }
            catch (Exception)
            {
                Assert.Fail("HabaneroApplicationException not thrown");
            }

            //---------------Test Result -----------------------
        }

        [Test]
        public void TestUpdatePrimaryKeyInfos_OneKey_OneColumn()
        {
            //This test shows that a Primary Key is not an alternate key.
            //---------------Set up test pack-------------------
            string tableName = GetRandomString();
            string columnName1 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetPrimaryKeyColumnsDataTable();
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, tableName, columnName1);
            //_schemaExtractorFake.PrimaryKeysDataTable = dataTable;
            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithColumn(tableName,columnName1);
            //--------------Assert PreConditions----------------
            Assert.AreEqual(1, dbTable.Columns.Count);
            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            _databaseReverseEngineerer.PopulatePrimaryKeyInfos(dbTable, dataTable);
            //---------------Test Result -----------------------
            DBPrimaryKey dbPrimaryKey = dbTable.PrimaryKeyDB;
            Assert.IsNotNull(dbPrimaryKey);
            Assert.IsNotNull(dbPrimaryKey.Table);

            BusinessObjectCollection<DBPrimaryKeyColumn> columnInfos = dbPrimaryKey.PrimaryKeyColumns;
            Assert.AreEqual(1, columnInfos.Count);
            DBPrimaryKeyColumn dbPrimaryKeyColumn = columnInfos[0];
            Assert.AreEqual(columnName1, dbPrimaryKeyColumn.Column.ColumnName);
        }

        [Test]
        public void TestUpdatePrimaryKeyInfos_OneKey_TwoColumn()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetPrimaryKeyColumnsDataTable();
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, columnName1);
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, columnName2);
            //_schemaExtractorFake.PrimaryKeysDataTable = dataTable;

            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithTwoColumn(null, columnName1, columnName2);

            //--------------Assert PreConditions----------------
            Assert.AreEqual(2, dbTable.Columns.Count);
            Assert.AreEqual(2, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            _databaseReverseEngineerer.PopulatePrimaryKeyInfos(dbTable, dataTable);

            //---------------Test Result -----------------------
            DBPrimaryKey dbPrimaryKey = dbTable.PrimaryKeyDB;
            Assert.IsNotNull(dbPrimaryKey);
            Assert.IsNotNull(dbPrimaryKey.Table);

            BusinessObjectCollection<DBPrimaryKeyColumn> columnInfos = dbPrimaryKey.PrimaryKeyColumns;
            Assert.AreEqual(2, columnInfos.Count);

            Assert.IsNotNull(dbPrimaryKey.GetColumnInfo(columnName1));
            Assert.IsNotNull(dbPrimaryKey.GetColumnInfo(columnName2));
        }

        [Test]
        public void TestUpdatePrimaryKeyInfos_OneKey_TwoColumn_OutOfMany()
        {
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            string columnName2 = GetRandomString();
            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithTwoColumn(null, columnName1, columnName2);
            dbTable.TableName = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetPrimaryKeyColumnsDataTable();
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, dbTable.TableName, columnName1);
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, dbTable.TableName, columnName2);
            _dbSchemaBuilder.CreatePrimaryKeyColumnDataRow(dataTable, GetRandomString(), columnName2);


            //--------------Assert PreConditions----------------
            Assert.AreEqual(3, dataTable.Rows.Count);
            Assert.AreEqual(2, dbTable.Columns.Count);

            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            _databaseReverseEngineerer.PopulatePrimaryKeyInfos(dbTable, dataTable);

            //---------------Test Result -----------------------
            DBPrimaryKey dbPrimaryKey = dbTable.PrimaryKeyDB;
            Assert.IsNotNull(dbPrimaryKey);
            Assert.IsNotNull(dbPrimaryKey.Table);

            BusinessObjectCollection<DBPrimaryKeyColumn> columnInfos = dbPrimaryKey.PrimaryKeyColumns;
            Assert.AreEqual(2, columnInfos.Count);

            Assert.IsNotNull(dbPrimaryKey.GetColumnInfo(columnName1));
            Assert.IsNotNull(dbPrimaryKey.GetColumnInfo(columnName2));
        }

        #endregion

        #region UniqueKey

        [Test]
        public void TestUpdateUniqueKeyInfos_FieldsNotLoaded()
        {
            //This test shows that a Alternate Key is not an alternate key.
            //---------------Set up test pack-------------------
            string columnName1 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetUniqueKeyColumnsDataTable();
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, columnName1 + "key", columnName1);
            //_schemaExtractorFake.UniqueKeysDataTable = dataTable;
            DBTable dbTable = new DBTable();

            //--------------Assert PreConditions----------------
            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            try
            {
                _databaseReverseEngineerer.PopulateUniqueKeyInfos(dbTable, dataTable);
                Assert.Fail("expected Err");
            }
            //---------------Test Result -----------------------
            catch (HabaneroApplicationException ex)
            {
                StringAssert.Contains("You cannot get the key for the table ", ex.Message);
                StringAssert.Contains("since the tables columns have not been loa", ex.Message);
            }

            //---------------Test Result -----------------------
        }

        [Test]
        public void TestUpdateUniqueKeyInfos_OneKey_OneColumn()
        {
            //This test shows that a Alternate Key is not an alternate key.
            //---------------Set up test pack-------------------
            string tableName = GetRandomString();
            string columnName1 = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetUniqueKeyColumnsDataTable();
            string keyName = columnName1 + "key";
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, tableName, keyName, columnName1);
            //_schemaExtractorFake.UniqueKeysDataTable = dataTable;

            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithColumn(tableName, columnName1);
            //--------------Assert PreConditions----------------
            Assert.AreEqual(1, dbTable.Columns.Count);

            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            _databaseReverseEngineerer.PopulateUniqueKeyInfos(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbTable.Keys.Count);
            DBKey alternateDBKey = dbTable.Keys[0];
            Assert.IsNotNull(alternateDBKey);
            Assert.IsNotNull(alternateDBKey.Table);
            Assert.AreEqual(keyName , alternateDBKey.KeyName);

            IList<DBKeyColumn> keyColumns = alternateDBKey.KeyColumns;
            Assert.AreEqual(1, keyColumns.Count, "Should be one column");
            DBKeyColumn dbKeyColumn = keyColumns[0];
            Assert.IsNotNull(dbKeyColumn.Column);
            Assert.AreEqual(columnName1, dbKeyColumn.Column.ColumnName);
        }

        [Test]
        public void TestUpdateUniqueKeyInfos_OneKey_TwoColumn()
        {
            //---------------Set up test pack-------------------
            const string columnName1 = "Column1";
            const string columnName2 = "Column2";
            const string keyName = "KeyName";
            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithTwoColumn(null, columnName1, columnName2);
            dbTable.TableName = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetUniqueKeyColumnsDataTable();
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, dbTable.TableName, keyName, columnName1);
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, dbTable.TableName, keyName, columnName2);
            //_schemaExtractorFake.UniqueKeysDataTable = dataTable;
            //--------------Assert PreConditions----------------
            Assert.AreEqual(2, dataTable.Rows.Count);
            Assert.AreEqual(2, dbTable.Columns.Count);
            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            _databaseReverseEngineerer.PopulateUniqueKeyInfos(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbTable.Keys.Count);
            DBKey alternateDBKey = dbTable.Keys[0];
            Assert.IsNotNull(alternateDBKey);
            Assert.IsNotNull(alternateDBKey.Table);
            Assert.AreEqual(keyName, alternateDBKey.KeyName);

            IList<DBKeyColumn> keyColumns = alternateDBKey.KeyColumns;
            Assert.AreEqual(2, keyColumns.Count, "Should be two columns");
            Assert.IsNotNull(alternateDBKey.GetColumnInfo(columnName1));
            Assert.IsNotNull(alternateDBKey.GetColumnInfo(columnName2));
        }

        [Test]
        public void TestUpdateUniqueKeyInfos_OneKey_TwoColumn_OutOfMany()
        {
            //---------------Set up test pack-------------------
            const string columnName1 = "Column1";
            const string columnName2 = "Column2";
            const string keyName = "KeyName";
            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithTwoColumn(null, columnName1, columnName2);
            dbTable.TableName = GetRandomString();
            DataTable dataTable = DBSchemaBuilder.GetUniqueKeyColumnsDataTable();
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, GetRandomString(), GetRandomString(), GetRandomString());
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, GetRandomString(), GetRandomString(), GetRandomString());
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, dbTable.TableName, keyName, columnName1);
            _dbSchemaBuilder.CreateUniqueKeyColumnDataRow(dataTable, dbTable.TableName, keyName, columnName2);
            //_schemaExtractorFake.UniqueKeysDataTable = dataTable;
            //--------------Assert PreConditions----------------
            Assert.AreEqual(4, dataTable.Rows.Count);
            Assert.AreEqual(2, dbTable.Columns.Count);
            //---------------Execute Test ----------------------
            //You must have the columns available for the table so that you
            //  can create the table.
            _databaseReverseEngineerer.PopulateUniqueKeyInfos(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, dbTable.Keys.Count);
            DBKey alternateDBKey = dbTable.Keys[0];
            Assert.IsNotNull(alternateDBKey);
            Assert.IsNotNull(alternateDBKey.Table);
            Assert.AreEqual(keyName, alternateDBKey.KeyName);

            IList<DBKeyColumn> keyColumns = alternateDBKey.KeyColumns;
            Assert.AreEqual(2, keyColumns.Count, "Should be two columns");
            Assert.IsNotNull(alternateDBKey.GetColumnInfo(columnName1));
            Assert.IsNotNull(alternateDBKey.GetColumnInfo(columnName2));
        }
        
        #endregion


        #region ForeignKey

        [Test]
        public void TestUpdateForeignKeys_NoneExist()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetForeignKeyColumnsDataTable();
            //_schemaExtractorFake.ForeignKeysDataTable = dataTable;
            DBTable dbTable = new DBTable();

            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateForeignKeys(dbTable, dataTable);
            //---------------Test Result -----------------------
            Assert.IsNotNull(dbTable.ForeignKeys);
            Assert.AreEqual(0, dbTable.ForeignKeys.Count);
        }

        [Test]
        public void TestUpdateForeignKeys_OneExist_MatchingTableDoesNotExist()
        {
            //---------------Set up test pack-------------------
            DataTable dataTable = DBSchemaBuilder.GetForeignKeyColumnsDataTable();
            const string foreignkeyName = "ForeignKey";
            const string foreignKeyTableName = "FK_TableName";
            const string foreignKeyColumnName = "FK_Column";
            const string referencedTableName = "ReferencedTableName";
            const string referencedColumnName = "RefColumnName";
            _dbSchemaBuilder.CreateForeignKeyColumnDataRow(dataTable, 
                foreignkeyName, foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, 1);
            //_schemaExtractorFake.ForeignKeysDataTable = dataTable;

            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithForeignKeyNoReferencedTable(foreignKeyTableName, foreignKeyColumnName);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dbTable.Database.Tables.Count);

            //---------------Execute Test ----------------------
            try
            {
                _databaseReverseEngineerer.PopulateForeignKeys(dbTable, dataTable);
                Assert.Fail("expected Err");
            }
            //---------------Test Result -----------------------
            catch (HabaneroApplicationException ex)
            {
                StringAssert.Contains("You cannot Update the Foreign Key " + foreignkeyName + " for table " + foreignKeyTableName, ex.Message);
                StringAssert.Contains("since the referenced table " + referencedTableName, ex.Message);
                StringAssert.Contains("does not exist in the schema", ex.Message);
            }

            //---------------Test Result -----------------------
        }

        [Test]
        public void TestUpdateForeignKeys_OneColumn()
        {
            //---------------Set up test pack-------------------
            const string foreignkeyName = "ForeignKey";
            const string foreignKeyTableName = "FK_TableName";
            const string foreignKeyColumnName = "FK_Column";
            const string referencedTableName = "ReferencedTableName";
            const string referencedColumnName = "RefColumnName";
            DataTable dataTable = DBSchemaBuilder.GetForeignKeyColumnsDataTable();
            _dbSchemaBuilder.CreateForeignKeyColumnDataRow(dataTable, 
                foreignkeyName, foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, 1);
            //_schemaExtractorFake.ForeignKeysDataTable = dataTable;

            DBTable referencedDBTable;
            DBTable dbTable = _testUtilsSchema.CreateTableInfoWithForeignKeyWithReferencedTable(foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, out referencedDBTable);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dataTable.Rows.Count);
            Assert.AreEqual(1, dbTable.Columns.Count);
            Assert.AreEqual(2, dbTable.Database.Tables.Count);

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateForeignKeys(dbTable, dataTable);

            //---------------Test Result -----------------------
            Assert.IsNotNull(dbTable.ForeignKeys);
            Assert.AreEqual(1, dbTable.ForeignKeys.Count);
            DBForeignKey dbForeignKey = dbTable.ForeignKeys[0];
            Assert.AreEqual(foreignkeyName, dbForeignKey.ForeignKeyName);
            Assert.AreEqual(foreignKeyTableName, dbForeignKey.ParentTable.TableName);
            Assert.AreEqual(1, dbForeignKey.ForeignKeyColumns.Count);
            DBForeignKeyColumn dbForeignKeyColumn = dbForeignKey.ForeignKeyColumns[0];
            Assert.IsNotNull(dbForeignKeyColumn.ParentColumn);
            Assert.IsNotNull(dbForeignKeyColumn.RelatedColumn);
            Assert.AreEqual(foreignKeyColumnName, dbForeignKeyColumn.ParentColumn.ColumnName);
            Assert.AreEqual(referencedTableName, dbForeignKey.RelatedTable.TableName);
            Assert.AreEqual(referencedColumnName, dbForeignKeyColumn.RelatedColumn.ColumnName);
        }

        [Test]
        public void TestUpdateForeignKeyInfo_OneForeignKey_TwoColumns()
        {
            //---------------Set up test pack-------------------
            const string foreignkeyName = "ForeignKey";
            const string foreignKeyTableName = "FK_TableName";
            const string foreignKeyColumnName = "FK_Column";
            const string foreignKeyColumnName2 = "FK_Column_2";
            const string referencedTableName = "ReferencedTableName";
            const string referencedColumnName = "RefColumnName";
            const string referencedColumnName2 = "RefColumnName_2";
            DataTable dataTable = DBSchemaBuilder.GetForeignKeyColumnsDataTable();
            _dbSchemaBuilder.CreateForeignKeyRowsWithTwoColumns(dataTable,
                foreignkeyName, foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, foreignKeyColumnName2, referencedColumnName2);
            //_schemaExtractorFake.ForeignKeysDataTable = dataTable;

            DBTable foreignKeyDBTable = _testUtilsSchema.CreateTableInfoForeignKeyWith2Columns_WithReferencedTable(foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, foreignKeyColumnName2, referencedColumnName2);

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, foreignKeyDBTable.Database.Tables.Count);
            Assert.AreEqual(2, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateForeignKeys(foreignKeyDBTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(1, foreignKeyDBTable.ForeignKeys.Count);
            DBForeignKey dbForeignKey = foreignKeyDBTable.ForeignKeys[0];
            Assert.AreEqual(2, dbForeignKey.ForeignKeyColumns.Count);

            DBForeignKeyColumn firstDBForeignKeyColumn = dbForeignKey.GetForeignKeyColumnInfo(foreignKeyColumnName);
            Assert.AreEqual(foreignKeyColumnName, firstDBForeignKeyColumn.ParentColumn.ColumnName);
            Assert.AreEqual(referencedColumnName, firstDBForeignKeyColumn.RelatedColumn.ColumnName);

            DBForeignKeyColumn secondDBForeignKeyColumn = dbForeignKey.GetForeignKeyColumnInfo(foreignKeyColumnName2);
            Assert.AreEqual(foreignKeyColumnName2, secondDBForeignKeyColumn.ParentColumn.ColumnName);
            Assert.AreEqual(referencedColumnName2, secondDBForeignKeyColumn.RelatedColumn.ColumnName);
        }


        [Test]
        public void TestUpdateForeignKeyInfo_TwoForeignKey_TwoColumns()
        {
            //---------------Set up test pack-------------------
            const string foreignkeyName = "ForeignKey";
            const string foreignKeyTableName = "FK_TableName";
            const string foreignKeyColumnName = "FK_Column";
            const string foreignKeyColumnName2 = "FK_Column_2";
            const string referencedTableName = "ReferencedTableName";
            const string referencedColumnName = "RefColumnName";
            const string referencedColumnName2 = "RefColumnName_2";
            DataTable dataTable = DBSchemaBuilder.GetForeignKeyColumnsDataTable();
            _dbSchemaBuilder.CreateForeignKeyRowsWithTwoColumns(dataTable, foreignkeyName, foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, foreignKeyColumnName2, referencedColumnName2);
            //_schemaExtractorFake.ForeignKeysDataTable = dataTable;

            const string anotherfk = "AnotherFK";
            _dbSchemaBuilder.CreateForeignKeyColumnDataRow(dataTable, anotherfk, foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, 1);

            DBTable foreignKeyDBTable = _testUtilsSchema.CreateTableInfoForeignKeyWith2Columns_WithReferencedTable(foreignKeyTableName, foreignKeyColumnName, referencedTableName, referencedColumnName, foreignKeyColumnName2, referencedColumnName2);

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, foreignKeyDBTable.Database.Tables.Count);
            Assert.AreEqual(3, dataTable.Rows.Count);

            //---------------Execute Test ----------------------
            _databaseReverseEngineerer.PopulateForeignKeys(foreignKeyDBTable, dataTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, foreignKeyDBTable.ForeignKeys.Count);
            Assert.AreNotEqual(foreignKeyDBTable.ForeignKeys[0], foreignKeyDBTable.ForeignKeys[1]);
            DBForeignKey compositeDBForeignKey = foreignKeyDBTable.GetForeignKeyInfo(foreignkeyName);
            Assert.AreEqual(2, compositeDBForeignKey.ForeignKeyColumns.Count);

            DBForeignKey simpleDBForeignKey = foreignKeyDBTable.GetForeignKeyInfo(anotherfk);
            Assert.AreEqual(1, simpleDBForeignKey.ForeignKeyColumns.Count);
        }
        #endregion

        #region TypeConversion

        [Test]
        public void Test_ConvertDataType_NoChangeIfConverterIsNull()
        {
            //---------------Set up test pack-------------------
            string dataType = GetRandomString();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            string convertedDataType = DatabaseReverseEngineerer.ConvertDataType(dataType, null);

            //---------------Test Result -----------------------
            Assert.AreEqual(dataType, convertedDataType);
        }

        [Test]
        public void Test_ConvertDataType_NoChangeIfMappingNotFound()
        {
            //---------------Set up test pack-------------------
            string dataType = GetRandomString();
            BusinessObjectCollection<TypeMapping> typeMappings = new BusinessObjectCollection<TypeMapping>();
            DBTypeConverter typeConverter = new DBTypeConverter(typeMappings);
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            string convertedDataType = DatabaseReverseEngineerer.ConvertDataType(dataType, typeConverter);

            //---------------Test Result -----------------------
            Assert.AreEqual(dataType, convertedDataType);
        }

        [Test]
        public void Test_ConvertDataType_ChangeToCustomMapping()
        {
            //---------------Set up test pack-------------------
            string dataType = GetRandomString();
            string customType = GetRandomString();
            BusinessObjectCollection<TypeMapping> typeMappings = new BusinessObjectCollection<TypeMapping>();
            TypeMapping typeMapping = new TypeMapping {FromType = dataType, ToType = customType};
            typeMappings.Add(typeMapping);

            DBTypeConverter typeConverter = new DBTypeConverter(typeMappings);
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            string convertedDataType = DatabaseReverseEngineerer.ConvertDataType(dataType, typeConverter);

            //---------------Test Result -----------------------
            Assert.AreNotEqual(dataType, convertedDataType);
            Assert.AreEqual(customType, convertedDataType);
        }
        
        private static string GetRandomString()
        {
            return RandomValueGen.GetRandomString();
        }
        #endregion

        #region CreateDatabaseInfo

        [Test]
        public void Test_CreateDatabaseInfo_WhenTwoDBRowReturnedFordatabaseName_ShouldCreateUsingFirstRow()
        {
            //This is a strange test but the interface for returning a databse is
            // the same as for returning any other Schema element and it thus returns a DataTable with
            // potentialy many datarows each representing a DataBase.
            //---------------Set up test pack-------------------
            var dbSchemaExtractor = new DBSchemaExtractor_Fake();
            var databasesDataTable = DBSchemaBuilder.GetDatabasesDataTable();
            dbSchemaExtractor.DatabasesDataTable = databasesDataTable;
            var dataRow1 = CreateRow(databasesDataTable);
            CreateRow(databasesDataTable);
            var reverseEngineer = CreateDatabaseReverseEngineerer(dbSchemaExtractor);
            
            //---------------Assert Precondition----------------
            Assert.AreEqual(2, databasesDataTable.Rows.Count);
            Assert.AreSame(databasesDataTable, dbSchemaExtractor.DatabasesDataTable);
            //---------------Execute Test ----------------------
            var databaseInfo = reverseEngineer.CreateDatabaseInfo(RandomValueGen.GetRandomString());
            //---------------Test Result -----------------------
            Assert.IsNotNull(databaseInfo);
            Assert.AreEqual(GetCatalogueName(dataRow1), databaseInfo.Catalog);
            Assert.AreEqual(GetSchemaName(dataRow1), databaseInfo.Schema);
        }

        private DatabaseReverseEngineerer CreateDatabaseReverseEngineerer(DBSchemaExtractor_Fake dbSchemaExtractor)
        {
            return new DatabaseReverseEngineerer(new ReverseEngineeringSettings(),  dbSchemaExtractor);
        }


        [Test]
        public void Test_CreateDatabaseInfo_WhenOneDBRowReturnedFordatabaseName_ShouldCreateUsingRow()
        {
            //This is a strange test but the interface for returning a databse is
            // the same as for returning any other Schema element and it thus returns a DataTable with
            // potentialy many datarows each representing a DataBase.
            //---------------Set up test pack-------------------
            var dbSchemaExtractor = new DBSchemaExtractor_Fake();
            var databasesDataTable = DBSchemaBuilder.GetDatabasesDataTable();
            dbSchemaExtractor.DatabasesDataTable = databasesDataTable;
            var dataRow1 = CreateRow(databasesDataTable);
            var reverseEngineer = CreateDatabaseReverseEngineerer(dbSchemaExtractor);
            
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, databasesDataTable.Rows.Count);
            Assert.AreSame(databasesDataTable, dbSchemaExtractor.DatabasesDataTable);
            //---------------Execute Test ----------------------
            var databaseInfo = reverseEngineer.CreateDatabaseInfo(RandomValueGen.GetRandomString());
            //---------------Test Result -----------------------
            Assert.IsNotNull(databaseInfo);
            Assert.AreEqual(GetCatalogueName(dataRow1), databaseInfo.Catalog);
            Assert.AreEqual(GetSchemaName(dataRow1), databaseInfo.Schema);
        }

        [Test]
        public void Test_CreateDatabaseInfo_WhenNoBRowReturnedFordatabaseName_ShouldRetNull()
        {
            //This is a strange test but the interface for returning a databse is
            // the same as for returning any other Schema element and it thus returns a DataTable with
            // potentialy many datarows each representing a DataBase.
            //---------------Set up test pack-------------------
            var dbSchemaExtractor = new DBSchemaExtractor_Fake();
            var databasesDataTable = DBSchemaBuilder.GetDatabasesDataTable();
            dbSchemaExtractor.DatabasesDataTable = databasesDataTable;
            var reverseEngineer = CreateDatabaseReverseEngineerer(dbSchemaExtractor);
            //---------------Assert Precondition----------------
            Assert.AreEqual(0, databasesDataTable.Rows.Count);
            Assert.AreSame(databasesDataTable, dbSchemaExtractor.DatabasesDataTable);
            //---------------Execute Test ----------------------
            var databaseInfo = reverseEngineer.CreateDatabaseInfo(RandomValueGen.GetRandomString());
            //---------------Test Result -----------------------
            Assert.IsNull(databaseInfo);
        }

        private static object GetSchemaName(DataRow dataRow1)
        {
            return dataRow1[DBSchemaTemplate.Naming.SchemaName];
        }

        private static object GetCatalogueName(DataRow dataRow1)
        {
            return dataRow1[DBSchemaTemplate.Naming.CatalogName];
        }
        private static DataRow CreateRow(DataTable databasesDataTable)
        {
            DataRow dataRow = databasesDataTable.NewRow();
            dataRow[DBSchemaTemplate.Naming.CatalogName] = GetRandomString();
            dataRow[DBSchemaTemplate.Naming.SchemaName] = GetRandomString();
            databasesDataTable.Rows.Add(dataRow);
            return dataRow;
        }

        #endregion

        #region Construct ReverseEngineering

        [Test]
        public void Test_CreateReverseEngineering_WhenSchemaExtractorNull_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            IDBSchemaExtractor dbSchemaExtractor = null;

            var reverseEngSettings = MockRepository.GenerateStub<IReverseEngineeringSettings>();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            try
            {
                new DatabaseReverseEngineerer(reverseEngSettings, dbSchemaExtractor);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("dbSchemaExtractor", ex.ParamName);
            }
        }
        [Test]
        public void Test_CreateReverseEngineering_WhenReverseEngineeringSettingNull_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            var dbSchemaExtractor = MockRepository.GenerateStub<IDBSchemaExtractor>();
            IReverseEngineeringSettings reverseEngSettings = null;
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            try
            {
                new DatabaseReverseEngineerer(reverseEngSettings, dbSchemaExtractor);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("reverseEngSettings", ex.ParamName);
            }
        }
     
        #endregion

        // ReSharper restore InconsistentNaming
    }


    public class DatabaseReverseEngineererSpy : DatabaseReverseEngineerer
    {
        public DatabaseReverseEngineererSpy(ReverseEngineeringSettings reverseEngineeringSettings, IDBSchemaExtractor dbSchemaExtractor):base(reverseEngineeringSettings, dbSchemaExtractor)
        {
        }
        public void ExtractColumnData(DataTable dataTable)
        {
            _columnsDataTable = dataTable;
        }
    }

    public static class DataTableAssertExtensions
    {

        public static void AssertIsView(this DataRow tableInfoDataRow)
        {
            Assert.AreEqual("VIEW", GetTableType(tableInfoDataRow).ToUpper());
        }

        private static string GetTableType(DataRow tableInfoDataRow)
        {
            return ((string)DBUtilities.ConvertDBNullToNull(tableInfoDataRow[DBSchemaTemplate.Naming.TableType]));
        }
    }
}
